
#include "stdafx.h"
#include "ConstDef.h"
#include "ReloadCode.h"
#include "ReloadApp.h"
#include "ReloadPacket.h"
#include "ReloadOverlay.h"
#include "ReloadConfigure.h"

namespace reload
{
	ResourceId::ResourceId()
	{

	}

	ResourceId::ResourceId( const std::vector<asyframe::byte>& _array )
	{
		R0(setValue(_array));
	}

	ResourceId::ResourceId( const char* _cstr )
	{
		R0(setValue(_cstr));
	}

	ResourceId::ResourceId( const std::string& _str )
	{
		R0(setValue(_str));
	}

	ResourceId::~ResourceId()
	{

	}

	retT ResourceId::setValue( const std::vector<asyframe::byte>& _array )
	{
		array_.clear();
		array_.resize(_array.size());
		std::copy(_array.begin(), _array.end(), array_.begin());
		RETSUCCESS;
	}

	retT ResourceId::setValue( const char* _cstr )
	{
		array_.clear();
		array_.resize(strlen(_cstr));
		for(std::size_t i = 0; i < array_.size(); ++i)
			array_[i] = (asyframe::byte)_cstr[i];
		RETSUCCESS;
	}

	retT ResourceId::setValue( const std::string& _str )
	{
		array_.clear();
		array_.resize(_str.length());
		for(std::size_t i = 0; i < array_.size(); ++i)
			array_[i] = (asyframe::byte)_str[i];
		RETSUCCESS;
	}

	std::string ResourceId::toString()
	{
		if(array_.size() > 0)
			return std::string((char*)&array_[0], array_.size());
		return std::string();
	}

	//////////////////////////////////////////////////////////////////////////////////////

	NodeId::NodeId()
	:array_()
	{

	}

	NodeId::NodeId( std::size_t _nodeIdLength, bool _isWildcard )
	{
		if(_isWildcard)
			setWildcard(_nodeIdLength);
		else
			setZero(_nodeIdLength);
	}

	NodeId::NodeId( const NodeId& _nodeId )
		:PacketElement(_nodeId)
	{
		array_.clear();
		array_.resize(_nodeId.array_.size());
		std::copy(_nodeId.array_.begin(), _nodeId.array_.end(), array_.begin());
	}

	NodeId::NodeId( std::size_t _bitSet, std::size_t _nodeIdLength )
	{
		setBit(_bitSet, _nodeIdLength);
	}

	NodeId::NodeId( const ResourceId& _resourceId, std::size_t _nodeIdLength )
		:PacketElement(_resourceId)
	{
		array_.clear();
		array_.resize(_nodeIdLength);
		std::size_t sizeToCopy = 0;
		if(_resourceId.array_.size() < _nodeIdLength)
		{
			sizeToCopy = _resourceId.array_.size();
			for(std::size_t i = _resourceId.array_.size(); i < _nodeIdLength; ++i)
				array_[i] = 0;
		}
		else
			sizeToCopy = _nodeIdLength;
		std::copy(_resourceId.array_.begin(), _resourceId.array_.begin() + sizeToCopy, array_.begin());
	}

	NodeId::~NodeId()
	{
		array_.clear();
	}

	retT NodeId::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		if(boost::shared_ptr<ReloadPacket> pReloadPacket = boost::dynamic_pointer_cast<ReloadPacket>(pRootElement_.lock()))
		{
			array_.clear();
			array_.resize(boost::dynamic_pointer_cast<ReloadApp>(asyframe::getApp())->getReloadConfigure()->overlay_[pReloadPacket->forwardingHeader_.overlay_].nodeIdLength_);
		}
		else
			RET(ERROR_COMMON_SHARED_PTR_NULL);
		R(_pBuffer->read(&array_[0], array_.size()));
		READFROMBUFFER_END;
	}

	retT NodeId::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		R(_pBuffer->write(&array_[0], array_.size()));
		WRITETOBUFFER_END;
	}

	std::size_t NodeId::size()
	{
		return array_.size();
	}

	std::string reload::NodeId::toString()
	{
		if(array_.size() == 0)
			return std::string();
		std::string result;
		asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
		if(std::size_t i = array_.size()/sizeof(asyframe::uint32))
		{
			do 
			{
				--i;
				result += (boost::format( "%X" ) % pArray[i]).str();
			} while (i != 0);
		}
		return result; 
	}

	bool NodeId::isZero() const
	{
		bool result = true;
		if(array_.size() == 0)
			return true;
		asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
		for(std::size_t i = 0; i < array_.size()/sizeof(asyframe::uint32); ++i)
		{
			if(pArray[i] != 0)
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool NodeId::isWildcard() const
	{
		bool result = true;
		if(array_.size() == 0)
			return false;
		asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
		for(std::size_t i = 0; i < array_.size()/sizeof(asyframe::uint32); ++i)
		{
			if(pArray[i] != ~((asyframe::uint32)0))
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool NodeId::isNULL() const
	{
		if(array_.size() == 0)
			return true;
		return false;
	}

	void NodeId::setNULL()
	{
		array_.clear();
	}

	void NodeId::setZero( std::size_t _nodeIdLength )
	{
		array_.clear();
		array_.resize(_nodeIdLength);
		asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
		for(std::size_t i = 0; i < _nodeIdLength/sizeof(asyframe::uint32); i++)
			pArray[i] = 0;
	}

	void NodeId::setWildcard( std::size_t _nodeIdLength )
	{
		array_.clear();
		array_.resize(_nodeIdLength);
		asyframe::uint32* pArray = (asyframe::uint32*)&array_[0];
		for(std::size_t i = 0; i < _nodeIdLength/sizeof(asyframe::uint32); i++)
			pArray[i] = ~((asyframe::uint32)0);
	}

	void NodeId::setBit( std::size_t _bitSet, std::size_t _nodeIdLength )
	{
		setZero(_nodeIdLength);
		_bitSet %= (_nodeIdLength*8);
		array_[_bitSet/(sizeof(asyframe::byte)*8)] = (asyframe::byte)(1 << (_bitSet%(sizeof(asyframe::byte)*8)));
	}

	const NodeId& NodeId::ZERO( std::size_t _nodeIdLength )
	{
		static const NodeId zero128(16),zero160(20);
		if(_nodeIdLength == 20)
			return zero160;
		return zero128;
	}

	const NodeId& NodeId::WILDCARD( std::size_t _nodeIdLength )
	{
		static const NodeId wildcard128(16,true),wildcard160(20,true);
		if(_nodeIdLength == 20)
			return wildcard160;
		return wildcard128;
	}

	const NodeId& NodeId::BITSET( std::size_t _bitSet, std::size_t _nodeIdLength )
	{
		static const class BitSetArray
		{
		public:
			BitSetArray()
			{
				for(std::size_t i = 0; i < 128; ++i)
					bitSet128[i].setBit(i, 16);
				bitSet128[128].setZero(16);
				for(std::size_t i = 0; i < 160; ++i)
					bitSet160[i].setBit(i, 20);
				bitSet160[160].setZero(20);
			}
			NodeId bitSet128[129];
			NodeId bitSet160[161];
		} bitSetArray;
		if(_nodeIdLength == 20)
			return bitSetArray.bitSet160[_bitSet];
		return bitSetArray.bitSet128[_bitSet];
	}

	bool NodeId::operator>( const ResourceId& _resourceId ) const
	{
		std::size_t matchSize = 0;
		if(array_.size() > _resourceId.array_.size())
		{
			matchSize = _resourceId.array_.size();
			for(std::size_t i = _resourceId.array_.size(); i < array_.size(); ++i)
			{
				if(array_[i] != 0)
				{
					return true;
				}
			}
		}
		else
			matchSize = array_.size();
		bool result = false;
		for(int i = matchSize -1; i >= 0; --i)
		{
			if(array_[i] == _resourceId.array_[i])
			{
				continue;
			}
			else if(array_[i] > _resourceId.array_[i])
			{
				result = true;
				break;
			}
			else
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool NodeId::operator==( const ResourceId& _resourceId ) const
	{
		std::size_t matchSize = 0;
		if(array_.size() > _resourceId.array_.size())
		{
			matchSize = _resourceId.array_.size();
			for(std::size_t i = _resourceId.array_.size(); i < array_.size(); ++i)
			{
				if(array_[i] != 0)
				{
					return false;
				}
			}
		}
		else
			matchSize = array_.size();
		bool result = true;
		for(std::size_t i = 0; i < matchSize; ++i)
		{
			if(array_[i] != _resourceId.array_[i])
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool NodeId::operator!=( const ResourceId& _resourceId ) const
	{
		return !operator==(_resourceId);
	}

	bool NodeId::operator<( const ResourceId& _resourceId ) const
	{
		return !operator>=(_resourceId);
	}

	bool NodeId::operator>=( const ResourceId& _resourceId ) const
	{
		return operator>(_resourceId)||operator==(_resourceId);
	}

	bool NodeId::operator<=( const ResourceId& _resourceId ) const
	{
		return operator<(_resourceId)||operator==(_resourceId);
	}

	const NodeId& NodeId::operator=( const NodeId& _nodeId )
	{
		PacketElement::operator=(_nodeId);
		array_.clear();
		array_.resize(_nodeId.array_.size());
		std::copy(_nodeId.array_.begin(), _nodeId.array_.end(), array_.begin());
		return *this;
	}

	NodeId::operator ResourceId() const
	{
		ResourceId resourceId;
		resourceId.array_.clear();
		resourceId.array_.resize(array_.size());
		std::copy(array_.begin(), array_.end(), resourceId.array_.begin());
		return resourceId;
	}

	bool operator>( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		std::size_t compCount = (_nodeIdLeft.array_.size()<=_nodeIdRight.array_.size()?_nodeIdLeft.array_.size():_nodeIdRight.array_.size())/sizeof(asyframe::uint32);
		asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
		asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
		bool result = false;
		for(int i = compCount - 1; i >= 0; --i)
		{
			if(pLeft[i] == pRight[i])
			{
				continue;
			}
			else if(pLeft[i] > pRight[i])
			{
				result = true;
				break;
			}
			else
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool operator==( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
			return false;
		std::size_t compCount = _nodeIdLeft.array_.size()/sizeof(asyframe::uint32);
		asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
		asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
		bool result = true;
		for(int i = compCount - 1; i >= 0; --i)
		{
			if(pLeft[i] != pRight[i])
			{
				result = false;
				break;
			}
		}
		return result;
	}

	bool operator!=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		return !(_nodeIdLeft==_nodeIdRight);
	}

	bool operator<( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		return !(_nodeIdLeft>=_nodeIdRight);
	}

	bool operator>=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		return _nodeIdLeft>_nodeIdRight||_nodeIdLeft==_nodeIdRight;
	}

	bool operator<=( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		return _nodeIdLeft<_nodeIdRight||_nodeIdLeft==_nodeIdRight;
	}

	NodeId operator~( const NodeId& _nodeId )
	{
		std::size_t compCount = _nodeId.array_.size()/sizeof(asyframe::uint32);
		asyframe::uint32* pArray = (asyframe::uint32*)&_nodeId.array_[0];
		NodeId result;
		result.array_.resize(_nodeId.array_.size());
		asyframe::uint32* pResult = (asyframe::uint32*)&result.array_[0];
		for(std::size_t i = 0; i < compCount; ++i)
		{
			pResult[i] = ~pArray[i];
		}
		return result;
	}

	NodeId operator+( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
			return _nodeIdLeft;
		std::size_t compCount = _nodeIdLeft.array_.size()/sizeof(asyframe::uint32);
		asyframe::uint32* pLeft = (asyframe::uint32*)&_nodeIdLeft.array_[0];
		asyframe::uint32* pRight = (asyframe::uint32*)&_nodeIdRight.array_[0];
		NodeId result;
		result.array_.resize(_nodeIdLeft.array_.size());
		asyframe::uint32* pResult = (asyframe::uint32*)&result.array_[0];
		asyframe::uint32 c = 0;
		for(std::size_t i = 0; i < compCount; ++i)
		{
			pResult[i] = pLeft[i] + pRight[i] + c;
			if(c == 0)
			{
				if(pResult[i] < pLeft[i])
					c = 1;
			}
			else
			{
				if(pResult[i] > pLeft[i])
					c = 0;
			}
		}
		return result;
	}

	NodeId operator-( const NodeId& _nodeIdLeft, const NodeId& _nodeIdRight )
	{
		if(_nodeIdLeft.array_.size() != _nodeIdRight.array_.size())
			return _nodeIdLeft;
		return _nodeIdLeft+~_nodeIdRight+NodeId::BITSET(0, _nodeIdLeft.array_.size());
	}

	std::size_t hash_value( NodeId const& _nodeId )
	{
		boost::hash<std::size_t> shasher;
		if(_nodeId.array_.size() == 0)
			return 0;
		std::size_t* pArray = (std::size_t*)(&_nodeId.array_[0]);
		std::size_t result = shasher(pArray[0]);
		for(std::size_t i = 1; i < _nodeId.array_.size()/sizeof(std::size_t); ++i)
		{
			result ^= shasher(pArray[i]);
		}
		return result;
	}

	////////////////////////////////////////////////////////////////////////////////////

	ResourceIdAsNodeIdDistance::ResourceIdAsNodeIdDistance()
	{

	}

	ResourceIdAsNodeIdDistance::ResourceIdAsNodeIdDistance( const ResourceId& _resourceId, const NodeId& _relativeNodeId )
	:resourceId_(_resourceId),relativeNodeId_(_relativeNodeId)
	{

	}

	ResourceIdAsNodeIdDistance::~ResourceIdAsNodeIdDistance()
	{

	}

	ResourceIdAsNodeIdDistance::operator NodeId() const
	{
		NodeId nodeId;
		nodeId.array_.clear();
		nodeId.array_.resize(relativeNodeId_.array_.size());
		nodeId.setZero(relativeNodeId_.array_.size());
		std::size_t sizeToCopy = relativeNodeId_.array_.size() <= resourceId_.array_.size()?relativeNodeId_.array_.size():resourceId_.array_.size();
		for(std::size_t i = 0; i < sizeToCopy; ++i)
			nodeId.array_[i] = resourceId_.array_[i];
		return nodeId - relativeNodeId_;
	}

	bool operator>( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return (NodeId)_resourceIdAsNodeIdDistanceLeft > (NodeId)_resourceIdAsNodeIdDistanceRight;
	}

	bool operator==( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return (NodeId)_resourceIdAsNodeIdDistanceLeft == (NodeId)_resourceIdAsNodeIdDistanceRight;
	}

	bool operator!=( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return !(_resourceIdAsNodeIdDistanceLeft==_resourceIdAsNodeIdDistanceRight);
	}

	bool operator<( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return !(_resourceIdAsNodeIdDistanceLeft>=_resourceIdAsNodeIdDistanceRight);
	}

	bool operator>=( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return _resourceIdAsNodeIdDistanceLeft>_resourceIdAsNodeIdDistanceRight||_resourceIdAsNodeIdDistanceLeft==_resourceIdAsNodeIdDistanceRight;
	}

	bool operator<=( const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceLeft, const ResourceIdAsNodeIdDistance& _resourceIdAsNodeIdDistanceRight )
	{
		return _resourceIdAsNodeIdDistanceLeft<_resourceIdAsNodeIdDistanceRight||_resourceIdAsNodeIdDistanceLeft==_resourceIdAsNodeIdDistanceRight;
	}

	std::size_t hash_value( ResourceIdAsNodeIdDistance const& _resourceIdAsNodeIdDistance )
	{
		return hash_value(_resourceIdAsNodeIdDistance.resourceId_);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////

	IPv4AddrPort::IPv4AddrPort()
	:addr_(),port_(0)
	{

	}

	IPv4AddrPort::~IPv4AddrPort()
	{
		port_ = 0;
	}

	retT IPv4AddrPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		asyframe::uint32 addr;
		R(_pBuffer->ntohRead(addr));
		addr_ = boost::asio::ip::address_v4(addr);
		R(_pBuffer->ntohRead(port_));
		READFROMBUFFER_END;
	}

	retT IPv4AddrPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		R(_pBuffer->htonWrite((asyframe::uint32)addr_.to_ulong()));
		R(_pBuffer->htonWrite(port_));
		WRITETOBUFFER_END;
	}

	std::size_t IPv4AddrPort::size()
	{
		return sizeof(asyframe::uint32) + sizeof(port_);
	}

	////////////////////////////////////////////////////////////////////////////////////////////

	IPv6AddrPort::IPv6AddrPort()
	:addr_(),port_(0)
	{

	}

	IPv6AddrPort::~IPv6AddrPort()
	{
		port_ = 0;
	}

	retT IPv6AddrPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		boost::asio::ip::address_v6::bytes_type addr;
		R(_pBuffer->read(addr.c_array(), sizeof(boost::asio::ip::address_v6::bytes_type)));
		addr_ = boost::asio::ip::address_v6(addr);
		R(_pBuffer->ntohRead(port_));
		READFROMBUFFER_END;
	}

	retT IPv6AddrPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		R(_pBuffer->write(addr_.to_bytes().c_array(), sizeof(boost::asio::ip::address_v6::bytes_type)));
		R(_pBuffer->htonWrite(port_));
		WRITETOBUFFER_END;
	}

	std::size_t IPv6AddrPort::size()
	{
		return sizeof(boost::asio::ip::address_v6::bytes_type) + sizeof(port_);
	}

	//////////////////////////////////////////////////////////////////////////////////////////////

	IpAddressPort::IpAddressPort()
	:type_(AddressType_ReservedAddr),length_(0),port_(0)
	{

	}

	IpAddressPort::IpAddressPort( const boost::asio::ip::address& _addr, asyframe::uint16 _port )
	:type_(AddressType_ReservedAddr),length_(0),addr_(_addr),port_(_port)
	{
		if(addr_.is_v4())
			type_ = AddressType_Ipv4Address;
		else if(addr_.is_v6())
			type_ = AddressType_Ipv6Address;
		else
			return;
		length_ = size() - sizeof(type_) - sizeof(length_);
	}

	IpAddressPort::~IpAddressPort()
	{
		type_ = AddressType_ReservedAddr;
		length_ = 0;
		port_ = 0;
	}

	retT IpAddressPort::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		R(_pBuffer->ntohRead(type_));
		R(_pBuffer->ntohRead(length_));
		switch(type_)
		{
		case AddressType_Ipv4Address:
			{
				IPv4AddrPort       v4AddrPort;
				R(v4AddrPort.readFromBuffer(_pBuffer));
				addr_ = v4AddrPort.addr_;
				port_ = v4AddrPort.port_;
				break;
			}
		case AddressType_Ipv6Address:
			{
				IPv6AddrPort       v6AddrPort;
				R(v6AddrPort.readFromBuffer(_pBuffer));
				addr_ = v6AddrPort.addr_;
				port_ = v6AddrPort.port_;
				break;
			}
		default:R(_pBuffer->consume(length_));RET(INFO_PROTOCOL_RELOAD_IPADDRESSPORT_UNKNOWN_TYPE);
		}
		READFROMBUFFER_END;
	}

	retT IpAddressPort::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		R(_pBuffer->htonWrite(type_));
		length_ = size() - sizeof(type_) - sizeof(length_);
		R(_pBuffer->htonWrite(length_));
		switch(type_)
		{
		case AddressType_Ipv4Address:
			{
				IPv4AddrPort       v4AddrPort;
				v4AddrPort.addr_ = addr_.to_v4();
				v4AddrPort.port_ = port_;
				v4AddrPort.writeToBuffer(_pBuffer);
				break;
			}
		case AddressType_Ipv6Address:
			{
				IPv6AddrPort       v6AddrPort;
				v6AddrPort.addr_ = addr_.to_v6();
				v6AddrPort.port_ = port_;
				v6AddrPort.writeToBuffer(_pBuffer);
				break;
			}
		default:R(_pBuffer->produce(length_));RET(INFO_PROTOCOL_RELOAD_IPADDRESSPORT_UNKNOWN_TYPE);
		}
		WRITETOBUFFER_END;
	}

	std::size_t IpAddressPort::size()
	{
		std::size_t totalSize = 0;
		totalSize += sizeof(type_);
		totalSize += sizeof(length_);
		switch(type_)
		{
		case AddressType_Ipv4Address:
			{
				IPv4AddrPort       v4AddrPort;
				v4AddrPort.addr_ = addr_.to_v4();
				v4AddrPort.port_ = port_;
				totalSize += v4AddrPort.size();
				break;
			}
		case AddressType_Ipv6Address:
			{
				IPv6AddrPort       v6AddrPort;
				v6AddrPort.addr_ = addr_.to_v6();
				v6AddrPort.port_ = port_;
				totalSize += v6AddrPort.size();
				break;
			}
		default:totalSize += length_;
		}
		return totalSize;
	}

	std::size_t hash_value( IpAddressPort const& _ipAddressPort )
	{
		IpAddressPort ipAddressPort(_ipAddressPort);
		boost::hash<std::size_t> shasher;
		std::vector<asyframe::byte> vecBuf;
		vecBuf.resize((ipAddressPort.size()/sizeof(std::size_t) + 1) * sizeof(std::size_t), 0);
		boost::shared_ptr<asyframe::IoBuffer> pBuffer(new asyframe::IoBuffer(&vecBuf));
		ipAddressPort.writeToBuffer(pBuffer);
		if(vecBuf.size() == 0)
			return 0;
		std::size_t* pArray = (std::size_t*)(&vecBuf[0]);
		std::size_t result = shasher(pArray[0]);
		for(std::size_t i = 1; i < vecBuf.size()/sizeof(std::size_t); ++i)
		{
			result ^= shasher(pArray[i]);
		}
		return result;
	}

	bool operator==( const IpAddressPort& _ipAddressPortLeft, const IpAddressPort& _ipAddressPortRight )
	{
		if(_ipAddressPortLeft.type_ != _ipAddressPortRight.type_)
			return false;
		if(_ipAddressPortLeft.length_ != _ipAddressPortRight.length_)
			return false;
		if(_ipAddressPortLeft.addr_ != _ipAddressPortRight.addr_)
			return false;
		if(_ipAddressPortLeft.port_ != _ipAddressPortRight.port_)
			return false;
		return true;
	}

	///////////////////////////////////////////////////////////////////////////////////////////

	DestinationData::DestinationData()
	:pType_(NULL),pLength_(NULL)
	{

	}

	DestinationData::~DestinationData()
	{
		pType_ = NULL;
		pLength_ = NULL;
	}

	retT DestinationData::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		if(pType_)
		{
			switch(*pType_)
			{
			case DestinationType_Node:R(nodeId_.readFromBuffer(_pBuffer));break;
			case DestinationType_Resource:R(resourceId_.readFromBuffer(_pBuffer));break;
			case DestinationType_Opaque:R(opaqueId_.readFromBuffer(_pBuffer));break;
			default:
				{
					if(pLength_)
					{
						R(_pBuffer->consume(*pLength_));
					}
					else
					{
						RET(ERROR_COMMON_PTR_NULL);
					}
					RET(INFO_PROTOCOL_RELOAD_DESTINATIONDATA_UNKNOWN_TYPE);
				}
			}
		}
		else
			RET(ERROR_COMMON_PTR_NULL);
		READFROMBUFFER_END;
	}

	retT DestinationData::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		if(pType_)
		{
			switch(*pType_)
			{
			case DestinationType_Node:R(nodeId_.writeToBuffer(_pBuffer));break;
			case DestinationType_Resource:R(resourceId_.writeToBuffer(_pBuffer));break;
			case DestinationType_Opaque:R(opaqueId_.writeToBuffer(_pBuffer));break;
			default:
				{
					if(pLength_)
					{
						R(_pBuffer->produce(*pLength_));
					}
					else
					{
						RET(ERROR_COMMON_PTR_NULL);
					}
					RET(INFO_PROTOCOL_RELOAD_DESTINATIONDATA_UNKNOWN_TYPE);
				}
			}
		}
		else
			RET(ERROR_COMMON_PTR_NULL);
		WRITETOBUFFER_END;
	}

	std::size_t DestinationData::size()
	{
		std::size_t totalSize = 0;
		if(pType_)
		{
			switch(*pType_)
			{
			case DestinationType_Node:totalSize += nodeId_.size();break;
			case DestinationType_Resource:totalSize += resourceId_.size();break;
			case DestinationType_Opaque:totalSize += opaqueId_.size();break;
			default:if(pLength_) totalSize += *pLength_;
			}
		}
		return totalSize;
	}

	retT DestinationData::attachRootElement( boost::weak_ptr<asyframe::PacketElement> _pRootElement )
	{
		R(asyframe::PacketElement::attachRootElement(_pRootElement));
		R(nodeId_.attachRootElement(_pRootElement));
		R(resourceId_.attachRootElement(_pRootElement));
		R(opaqueId_.attachRootElement(_pRootElement));
		RETSUCCESS;
	}

	///////////////////////////////////////////////////////////////////////////////////////////

	Destination::Destination()
	:opaqueId_(0),type_(DestinationType_Reserved),length_(0)
	{
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
	}

	Destination::Destination( const NodeId& _nodeId )
	:PacketElement(_nodeId),opaqueId_(0),type_(DestinationType_Node),length_(0)
	{
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
		destinationData_.nodeId_ = _nodeId;
		length_ = destinationData_.size();
	}

	Destination::Destination( const ResourceId& _resourceId )
	:PacketElement(_resourceId),opaqueId_(0),type_(DestinationType_Resource),length_(0)
	{
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
		destinationData_.resourceId_ = _resourceId;
		length_ = destinationData_.size();
	}

	Destination::Destination( const Destination& _destination )
	:PacketElement(_destination),opaqueId_(_destination.opaqueId_),type_(_destination.type_),length_(_destination.length_),destinationData_(_destination.destinationData_)
	{
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
	}

	Destination::Destination( const asyframe::uint16& _opaqueId )
	:opaqueId_(_opaqueId),type_(DestinationType_Reserved),length_(0)
	{
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
	}

	Destination::~Destination()
	{
		opaqueId_ = 0;
		type_ = DestinationType_Reserved;
		length_ = 0;
	}

	retT Destination::readFromBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		READFROMBUFFER_START;
		asyframe::byte firstByte = 0;
		R(_pBuffer->ntohPeek(firstByte));
		if(firstByte >> (sizeof(asyframe::byte)*8 - 1))
		{
			R(_pBuffer->ntohRead(opaqueId_));
		}
		else
		{
			R(_pBuffer->ntohRead(type_));
			R(_pBuffer->ntohRead(length_));
			R(destinationData_.readFromBuffer(_pBuffer));
		}
		READFROMBUFFER_END;
	}

	retT Destination::writeToBuffer( boost::shared_ptr<asyframe::IoBuffer> _pBuffer )
	{
		WRITETOBUFFER_START;
		if(opaqueId_ >> (sizeof(opaqueId_)*8 - 1))
		{
			R(_pBuffer->htonWrite(opaqueId_));
		}
		else
		{
			R(_pBuffer->htonWrite(type_));
			R(_pBuffer->htonWrite(length_));
			R(destinationData_.writeToBuffer(_pBuffer));
		}
		WRITETOBUFFER_END;
	}

	std::size_t Destination::size()
	{
		std::size_t totalSize = 0;
		if(opaqueId_ >> (sizeof(opaqueId_)*8 - 1))
		{
			totalSize += sizeof(opaqueId_);
		}
		else
		{
			totalSize += sizeof(type_);
			totalSize += sizeof(length_);
			totalSize += destinationData_.size();
		}
		return totalSize;
	}

	retT Destination::attachRootElement( boost::weak_ptr<asyframe::PacketElement> _pRootElement )
	{
		R(asyframe::PacketElement::attachRootElement(_pRootElement));
		R(destinationData_.attachRootElement(_pRootElement));
		RETSUCCESS;
	}

	const Destination& Destination::operator=( const Destination& _destination )
	{
		PacketElement::operator=(_destination);
		opaqueId_ = _destination.opaqueId_;
		type_ = _destination.type_;
		length_ = _destination.length_;
		destinationData_ = _destination.destinationData_;
		destinationData_.pType_ = &type_;
		destinationData_.pLength_ = &length_;
		return *this;
	}
} /*namespace reload*/
